# 添加的视图文件
import logging
# base64加密算法
import base64

import logger
# 用于渲染模板文件，将数据传递给 HTML 模板 render:提供、递交
from django.shortcuts import render
# 用于返回 JSON 格式的数据响应
from django.http import JsonResponse
# 用于解析前端发送的 JSON 数据
from rest_framework.parsers import JSONParser
# Django REST framework 提供的装饰器，用于定义视图函数支持的 HTTP 方法
from rest_framework.decorators import api_view
# 在 Django 的 ORM（Object-Relational Mapping，对象关系映射）中，Q 是一个用于构建复杂查询的工具，
# 它允许你使用布尔逻辑（如 AND(&)、OR(|) 和 NOT(~)）来组合多个查询条件。Q 对象是 django.db.models.Q 类的实例，主要用于在 QuerySet 中实现复杂的查询逻辑
from django.db.models import Q
# 从 models.py 中导入的用户模型类，用于操作数据库
from .models import User, Address, Storeinfo
# random:用于生成随机数,string:包含各种字符串常量和字符串处理的函数，例如字母、数字等字符集合
import random, string
# Django 的缓存框架用于存储数据以加快数据访问速度，减少数据库查询次数。cache 对象提供了基本的缓存操作，如设置、获取和删除缓存数据,cashe:高速缓冲存储器
from django.core.cache import cache
# Signer(签名者) 类用于创建和验证数字签名，通常用于确保数据在传输过程中未被篡改。这在处理 cookie 或其他需要安全传输的数据时非常有用
from django.core.signing import Signer
# timedelta 表示两个日期或时间之间的差异。它可以用来计算时间间隔，例如“30天”或“2小时”
from datetime import timedelta
# 分组导包
from django.db.models import Sum, Count, Max, Min, Avg
# 用于分页
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
# 重点(用于视图类请求方式)
# IsAuthenticated 是 DRF (Django REST Framework) 提供的一个权限类，
# 用于限制只有通过认证的用户才能访问视图（特点：1、验证请求是否携带有效的用户凭证（如Session、Token等）
# 2、未认证用户会收到 401 Unauthorized 响应。3、简单直接：不需要额外配置即可使用）：
from rest_framework.permissions import IsAuthenticated
# APIView 是 DRF 提供的基类视图，用于创建处理HTTP请求的视图类：
from rest_framework.views import APIView
# Create your views here.


# 注册页面视图
def registerview(request):
    # 当用户访问注册页面时，Django会调用这个函数，并将register.html返回给用户
    return render(request, 'register.html')


# 辅助函数：判断数据是否为空
def is_empty(c):
    # 如果c是None或者c转为字符串后去除空格后为空字符串，则返回True，否则返回False
    return c is None or str(c).strip() == ''


# 定义一个公共的方法，登录成功后，使用用户名和密码采用base64加密算法生成token，并将token值返回客户端
def b64encodepassword(password):
    # 先把字符串转化为字节码
    bpassword = bytes(password, encoding='utf-8')
    # 进行base64编码
    b64password = base64.b64encode(bpassword).decode('utf-8')
    return b64password


# 产生token的方法
def createtoken(name):
    # 生成一个随机的字符串:这行代码使用 random.choices() 函数从 string.ascii_letters（包含所有大小写字母）中随机选择 8 个字符
    randomstr = ''.join(random.choices(string.ascii_letters, k=8))
    logging.info(f'看看随机生成的字符串{randomstr}')
    # 签名：签名可以确保数据的完整性和真实性，防止数据在传输过程中被篡改
    token = Signer().sign(randomstr+name)
    logging.info(f'看看随机生成的签名{token}')
    # 保存到内存中去：将令牌（签名）存储在缓存中   timeout=timedelta(minutes=100).total_seconds() 设置缓存的超时时间为 100 分钟
    cache.set(f'test_{name}', token, timeout=timedelta(minutes=100).total_seconds())
    # 返回token
    return token


# 鉴权（授权）方法
def checktoken(request):
    logging.info(f'看看request.META数据结构-对应postman中的headers:{request.META}')
    # 获取从前端传过来的tokan值：从 request.META 中获取名为 HTTP_TOKEN 的值。这通常用于从 HTTP 请求头中获取令牌
    gettoken = request.META.get('HTTP_TOKEN')
    logging.info(f'获取到的从前端传过来的tokan值:{gettoken}')
    if is_empty(gettoken) or (gettoken is None):
        return False, '请先登录!'
    # 将从前端传过来的tokan值反签名
    unsigntoken = Signer().unsign(gettoken)
    # 从反签名中的内容获取账号name
    name = unsigntoken[8:]
    # 检查内存中的token是否存在
    cachetoken = cache.get(f'test_{name}')
    logging.info(f'从缓存中获取到的token:{cachetoken}')
    if is_empty(cachetoken) or (cachetoken is None):
        return False, '内存无该token值,无缓存'
    logger.logger.info(f'已登录状态')
    # 说明token在缓存中，有效
    return True, f'{name}'


# 重点(视图类请求方式)
class Adus(APIView):
    # 权限控制（只有通过认证才能访问视图）
    permission_classes = [IsAuthenticated]
    # 处理POST请求
    def post(self, request):
        return JsonResponse({
            'message': 'post请求方式'
        })
    # 处理GET请求
    def get(self, request):
        return JsonResponse({
            'message': 'get请求方式'
        })
    # 处理DELETE请求
    def delete(self, request):
        return JsonResponse({
            'message': 'delete请求方式'
        })
    # 处理PUT请求
    def put(self, request):
        return JsonResponse({
            'message': 'put请求方式'
        })


# 视图函数
@api_view(['POST'])
def adduser(request):
    logging.info(f'看看Request长啥样：{request}')
    data = JSONParser().parse(request)
    logging.info(f'看看从前端得到的数据：{data}')
    name = data.get('name')
    password = data.get('password')
    age = data.get('age')
    gender = data.get('gender')

    if is_empty(name) or is_empty(password):
        return JsonResponse({
            "message": "用户名或密码为空"
        }, status=404)

    if User.objects.filter(name=name).exists() is True:
        return JsonResponse({
            "message": f"用户名:{name},已存在"
        }, status=404)

    try:
        # 使用User模型类创建一个新的用户对象，并调用save()方法将其保存到数据库中
        User(name=name, password=password, age=age, gender=gender).save()
        return JsonResponse({
            'message': f'用户：{name},注册成功'
        }, status=200)
    except Exception as e:
        return JsonResponse({
            "message": f"注册失败，出现了{e}错误"
        }, status=500)


# 视图函数
@api_view(['put'])
def updateuser(request):
    data = JSONParser().parse(request)
    itemid = data.get('itemid')
    name = data.get('name')
    password = data.get('password')
    age = data.get('age')
    gender = data.get('gender')

    # status不写默认200
    if is_empty(itemid):
        return JsonResponse({
            'message': 'itemid不能为空'
        }, status=404)

    # 根据Id值查询出数据对象
    obj = User.objects.get(id=itemid)
    logging.info(f'根据Id值查询出数据对象:{obj}')

    if is_empty(name) is False:
        obj.name = name

    if is_empty(password) is False:
        obj.password = password

    if is_empty(age) is False:
        obj.age = age

    if is_empty(gender) is False:
        obj.gender = gender

    # 保存数据对象
    obj.save()

    return JsonResponse({
        'message': '修改数据成功'
    })

# 删除数据
@api_view(['delete'])
def deleteuser(request):

    data = JSONParser().parse(request)
    itemid = data.get('itemid')

    if is_empty(itemid):
        return JsonResponse({
            'message': 'itemid不能为空'
        }, status=404)

    try:
        obj = User.objects.get(id=itemid)
        logging.info(f'delete-根据Id值查询出数据对象:{obj}')
        # 删除数据对象
        obj.delete()

        return JsonResponse({
            'message': '删除数据成功'
        })
    except Exception as e:
        return JsonResponse({
            'message': 'id不存在'
        })


# 查询数据
@api_view(['get'])
def getuser(request):

    # filter()内无参数时，查询所有
    allobj = User.objects.filter()
    # <QuerySet[ < User: zhangsan >, < User: wangwu >, < User: zhaoliu >, < User: 王蒙蒙 >, < User: 小天才 >, < User: 小王 >, < User: 狂徒张三 >] >
    logging.info(f'看看所有数据对象长什么样：{allobj}')
    l = []
    token = None
    for obj in allobj:
        logging.info(f'看看单个数据对象长什么样：{obj}')
        token = b64encodepassword(obj.password)
        l.append({
            "数据序号": obj.id,
            "姓名": obj.name,
            "年龄": obj.age,
            "性别": obj.gender,
        })
    logging.info(f'加入到列表中的数据：{l}')
    logging.info(f'token：{token}')

    return JsonResponse({
        "message": "查询成功",
        "data": l,
        "token": token
    })


# 条件查询
@api_view(['get'])
def getuser2(request):

    #  <QueryDict: {'name': ['小王'], 'age': ['18'], 'gender': ['T']}>
    logging.info(f'看看request.GET长什么样：{request.GET}')
    name = request.GET.get('name')
    logging.info(f'看看request.GET.get(name)长什么样：{name}')
    age = request.GET.get('age')
    gender = request.GET.get('gender')

    # filter()内无参数时，查询所有.filter(name=name, age=age, gender=gender)--and条件查询:有参数时为条件查询
    # 参数为：filter(Q(name=name) | Q(age=age) | Q(gender=gender))时，表or条件查询
    # 参数为：filter(Q(name=name) & Q(age=age) & Q(gender=gender))时，表and条件查询
    # 参数为：filter(~Q(name=name))时，表NOT条件查询
    allobj = User.objects.filter(Q(name=name) | Q(age=age) | Q(gender=gender))
    logging.info(f'看看所有数据对象长什么样：{allobj}')
    l = []

    for obj in allobj:
        logging.info(f'看看单个数据对象长什么样：{obj}')
        l.append({
            "数据序号": obj.id,
            "姓名": obj.name,
            "年龄": obj.age,
            "性别": obj.gender,
        })
    logging.info(f'加入到列表中的数据：{l}')

    return JsonResponse({
        "message": "查询成功",
        "data": l
    })


# 传什么就查询什么数据
@api_view(['get'])
def getuser3(request):

    flag, name = checktoken(request)

    if flag is False:
        logging.info(f'{name}')
        return JsonResponse({
            'message': name
        }, status=401)

    dic = {}
    logging.info(f'看看request.GET长什么样：{request.GET}')
    name = request.GET.get('name')
    logging.info(f'看看request.GET.get(name)长什么样：{name}')
    age = request.GET.get('age')
    gender = request.GET.get('gender')

    if is_empty(name) is False:
        dic['name'] = name

    if is_empty(age) is False:
        dic['age'] = age

    if is_empty(gender) is False:
        dic['gender'] = gender

    # filter(**dic) 相当于 ：filter(name=name, age=age, gender=gender)--and条件查询，但**dic你传一个查询条件就根据这个条件查询，而后者会报错
    allobj = User.objects.filter(**dic)
    # <QuerySet[ < User: zhangsan >, < User: wangwu >, < User: 狂徒张三 >] >
    logging.info(f'看看所有数据对象长什么样：{allobj}')
    l = []

    for obj in allobj:
        logging.info(f'看看单个数据对象长什么样：{obj}')
        l.append({
            "数据序号": obj.id,
            "姓名": obj.name,
            "年龄": obj.age,
            "性别": obj.gender,
        })
    logging.info(f'加入到列表中的数据：{l}')

    return JsonResponse({
        "message": "查询成功",
        "data": l
    })


@api_view(['get'])
def login(request):

    name = request.GET.get('name')
    password = request.GET.get('password')

    if is_empty(name) or is_empty(password):
        logging.info('用户名或密码错误')
        return JsonResponse({
            "message": "用户名或密码错误"
        })

    try:
        obj = User.objects.get(name=name)

        if obj.password == password:
            token = createtoken(name)
            logging.info(f'登录成功,token:{token}')
            return JsonResponse({
                "message": "登录成功",
                "token": token
            }, status=200)
        else:
            logging.info('密码不正确')
            return JsonResponse({
                "message": "密码不正确"
            }, status=404)
    except Exception as e:
        logging.info(f"用户名不存在！{e}")
        return JsonResponse({
            "message": f"用户名不存在！{e}"
        }, status=404)

# 添加地址信息
@api_view(['post'])
def addaddress(request):
    data = JSONParser().parse(request)
    address = data.get('address')

    Address(address=address).save()
    return JsonResponse({
        'message': '添加地址成功'
    })


# 添加店铺信息
@api_view(['post'])
def addstore(request):

    flag, name = checktoken(request)
    if flag is False:
        return JsonResponse({
            'message': name
        }, status=401)

    data = JSONParser().parse(request)
    name = data.get('name')
    goodprice = data.get('goodprice')
    created_time = data.get('created_time')
    updated_time = data.get('updated_time')
    address = data.get('address')
    # Storeinfo(name=name, goodprice=goodprice, addressinfo_id=addressid).save()

    try:
        if is_empty(name) is False:
            if Address.objects.filter(address=address).exists() is True:
                addressobj = Address.objects.get(address=address)
                Storeinfo(name=name, goodprice=goodprice, created_time=created_time, updated_time=updated_time,
                          addressinfo=addressobj).save()
                return JsonResponse({
                    'message': '添加店铺成功'
                })
            else:
                Address(address=address).save()
                addressobj = Address.objects.get(address=address)
                Storeinfo(name=name, goodprice=goodprice, created_time=created_time, updated_time=updated_time,
                          addressinfo=addressobj).save()
                return JsonResponse({
                    'message': '添加店铺成功'
                })

        else:
            return JsonResponse({
                'message': '店铺名为必填参数'
            }, status=404)
    except Exception as e:
        return JsonResponse({
            'message': '添加失败，内部错误{e}'
        }, status=500)

# 删除地址信息（也会删除对应的店铺信息，但删除店铺中的地址或店铺信息，不会影响地址信息）
@api_view(['delete'])
def deleteaddress(request):

    data = JSONParser().parse(request)
    addressid = data.get('addressid')
    addressobj = Address.objects.get(id=addressid)
    addressobj.delete()
    return JsonResponse({
        'message': '地址删除成功'
    })

# 根据地址信息查询店铺信息
@api_view(['get'])
def getaddress(request):

    id = request.GET.get('id')
    try:
        obj = Address.objects.get(id=id)
        lis = []
        return JsonResponse({
            'id': obj.id,
            'address': obj.address,
            'storename': obj.storeinfo.name,
            'price': obj.storeinfo.goodprice,
            'created_time': obj.storeinfo.created_time,
            'updated_time': obj.storeinfo.updated_time
        })
    except Exception as e:
        return JsonResponse({
            'message': f'内部错误{e}'
        }, status=500)

# 根据店铺信息查询地址信息
@api_view(['get'])
def getstoreinfo(request):

    id = request.GET.get('id')
    try:
        obj = Storeinfo.objects.get(id=id)
        lis = []
        return JsonResponse({
            'id': obj.id,
            'name': obj.name,
            'goodprice': obj.goodprice,
            'address': obj.addressinfo.address,
            'created_time': obj.addressinfo.created_time,
            'updated_time': obj.addressinfo.updated_time,
        })
    except Exception as e:
        return JsonResponse({
            'message': f'内部错误{e}'
        }, status=500)

# 查询店铺所有店铺信息
@api_view(['get'])
def getpostlist(request):

    objall = Storeinfo.objects.filter()

    lis = []

    for obj in objall:
        lis.append({
            'id': obj.id,
            'name': obj.name,
            'goodprice': obj.goodprice,
            'created_time': obj.created_time,
            'updated_time': obj.updated_time,
            'address': obj.addressinfo.address,
        })
    return JsonResponse({
        'message': '查询成功',
        'code': 200,
        'items': objall.count(),
        'data': lis
    })

# 查询店铺所有店铺信息并分页
@api_view(['get'])
def getdata_page(request):
    page = request.GET.get('page')
    page_size = request.GET.get('page_size')

    if is_empty(page) or is_empty(page_size):
        return JsonResponse({
            'message': '必填参数不能为空或不存在'
        })

    objall = Storeinfo.objects.filter()
    pageall = Paginator(objall, page_size)
    logger.logger.info(f'oageall:{pageall}')

    try:
        # 获取指定页码的数据
        pageobj = pageall.page(page)
    except PageNotAnInteger:
        pageobj = pageall.page(1)
    except EmptyPage:
        pageobj = pageall.page(pageall.num_pages)


    lis = []

    for obj in pageobj:
        lis.append({
            'id': obj.id,
            'name': obj.name,
            'goodprice': obj.goodprice,
            'created_time': obj.created_time,
            'updated_time': obj.updated_time,
            'address': obj.addressinfo.address,
        })
    return JsonResponse({
        'message': '查询成功',
        'code': 200,
        'items': objall.count(),
        'data': lis
    })

# 根据店铺ID查询数据
@api_view(['get'])
def getdata_id(request, id):

    if is_empty(id):
        return JsonResponse({
            'message': '必填参数不能为空或不存在,不存在该店铺'
        })

    obj = Storeinfo.objects.get(id=id)


    lis = []
    lis.append({
        'id': obj.id,
        'name': obj.name,
        'goodprice': obj.goodprice,
        'created_time': obj.created_time,
        'updated_time': obj.updated_time,
        'address': obj.addressinfo.address,
    })
    return JsonResponse({
        'message': '查询成功',
        'code': 200,
        'data': lis
    })

# 修改店铺信息
@api_view(['put'])
def getdata_put(request, id):

    if is_empty(id):
        return JsonResponse({
            'message': '必填参数不能为空或不存在,不存在该店铺'
        })
    values = JSONParser().parse(request)
    # id = values.get('id')
    name = values.get('name')
    goodprice = values.get('goodprice')
    created_time = values.get('created_time')
    updated_time = values.get('updated_time')
    address = values.get('address')
    obj = Storeinfo.objects.get(id=id)
    try:
        if is_empty(name) is False:
            obj.name = name
        if is_empty(goodprice) is False:
            obj.goodprice = goodprice
        if is_empty(created_time) is False:
            obj.created_time = created_time
        if is_empty(updated_time) is False:
            obj.updated_time = updated_time
        if is_empty(address) is False:
            if Address.objects.filter(address=address).exists() is True:
                obj.addressinfo = Address.objects.get(address=address)

        obj.save()
        lis = []
        lis.append({
            'id': obj.id,
            'name': obj.name,
            'goodprice': obj.goodprice,
            'created_time': obj.created_time,
            'updated_time': obj.updated_time,
            'address': obj.addressinfo.address,
        })
        return JsonResponse({
            'message': '修改成功',
            'code': 200,
            'data': lis
        })
    except Exception as e:
        return JsonResponse({
            'message': '修改失败, 内部错误{e}',
        }, status=500)

# 分组：
@api_view(['get'])
def getinfo(request):
    # 根据values()中的‘gender’分组，展示的数据为annotate()中的各项数据
    uservalues = User.objects.values('gender').annotate(nums=Count('id'),
                                                        maxrate=Max('age'),
                                                        minrate=Min('age'),
                                                        avgrate=Avg('age'),
                                                        sumrate=Sum('age'))
    logger.logger.info(f'看看得到的数据{uservalues}')
    return JsonResponse({
        'message': '查询成功'
    })

# 查询店铺所有店铺信息并分页-0表未删除，可展示，1表已删除，不展示
@api_view(['get'])
def getdata_page_isdelete(request):

    flag, name = checktoken(request)
    if flag is False:
        return JsonResponse({
            'message': name
        }, status=401)

    page = request.GET.get('page')
    page_size = request.GET.get('page_size')

    if is_empty(page) or is_empty(page_size):
        return JsonResponse({
            'message': '必填参数不能为空或不存在'
        })

    objall = Storeinfo.objects.filter(store_isdelete='0')
    pageall = Paginator(objall, page_size)
    logger.logger.info(f'oageall:{pageall}')

    try:
        # 获取指定页码的数据
        pageobj = pageall.page(page)
    except PageNotAnInteger:
        pageobj = pageall.page(1)
    except EmptyPage:
        pageobj = pageall.page(pageall.num_pages)


    lis = []

    for obj in pageobj:
        lis.append({
            'id': obj.id,
            'name': obj.name,
            'goodprice': obj.goodprice,
            'created_time': obj.created_time,
            'updated_time': obj.updated_time,
            'address': obj.addressinfo.address,
        })
    return JsonResponse({
        'message': '查询成功',
        'code': 200,
        'items': objall.count(),
        'data': lis
    })

# 删除店铺
@api_view(['delete'])
def delete_store(request, id):

    flag, name = checktoken(request)
    if flag is False:
        return JsonResponse({
            'message': name
        }, status=401)

    if is_empty(id) is True:
        return JsonResponse({
            'message': '删除失败，必填参数不能为空或不存在'
        }, status=404)

    try:
        if Storeinfo.objects.filter(id=id).exists() is True:
            obj = Storeinfo.objects.get(id=id)
            obj.store_isdelete = '1'
            obj.save()
            return JsonResponse({
                'message': '删除成功'
            }, status=201)
        else:
            return JsonResponse({
                'message': '删除失败,该商铺不存在'
            }, status=404)
    except Exception as e:
        return JsonResponse({
            'message': '删除失败，内部错误{e}'
        }, status=500)


# 获取所有地址信息
@api_view(['get'])
def getaddress_info(request):
    objall = Address.objects.filter()
    lis = []
    for obj in objall:
        lis.append({
            'value': obj.id,
            'label': obj.address,
        })

    return JsonResponse({
        'data': lis
    })


# 传什么就查询什么数据--条件查询--模糊查询
@api_view(['get'])
def getdata_seatch(request):

    flag, name = checktoken(request)
    if flag is False:
        return JsonResponse({
            'message': name
        }, status=401)

    dic = {}
    page = request.GET.get('page')
    page_size = request.GET.get('page_size')

    if is_empty(page) or is_empty(page_size):
        return JsonResponse({
            'message': '必填参数不能为空或不存在'
        })
    id = request.GET.get('id', None)
    name = request.GET.get('name', '')
    addressid = request.GET.get('addressid', '')
    dic['store_isdelete'] = '0'

    if is_empty(id) is False:
        dic['id'] = id

    if is_empty(name) is False:
        dic['name__contains'] = name

    if is_empty(addressid) is False:
        dic['addressinfo_id'] = addressid

    try:
        # filter(**dic) 相当于 ：filter(name=name, age=age, gender=gender)--and条件查询，但**dic你传一个查询条件就根据这个条件查询，而后者会报错
        allobj = Storeinfo.objects.filter(**dic)
        # <QuerySet[ < User: zhangsan >, < User: wangwu >, < User: 狂徒张三 >] >
        pageall = Paginator(allobj, page_size)
        try:
            # 获取指定页码的数据
            pageobj = pageall.page(page)
        except PageNotAnInteger:
            pageobj = pageall.page(1)
        except EmptyPage:
            pageobj = pageall.page(pageall.num_pages)

        lis = []

        for obj in pageobj:
            lis.append({
                'id': obj.id,
                'name': obj.name,
                'goodprice': obj.goodprice,
                'created_time': obj.created_time,
                'updated_time': obj.updated_time,
                'address': obj.addressinfo.address,
            })
        return JsonResponse({
            'message': '查询成功',
            'code': 200,
            'items': allobj.count(),
            'data': lis
        })
    except Exception as e:
        return JsonResponse({
            'message': '查询失败, 内部错误{e}'
        }, status=500)

